﻿using System.Reflection;
using System.Reflection.Emit;

/*
        public class DynClass
        {
            private int m_number;

            public DynClass() : this(42) {}
            public DynClass(int initNumber)
            {
                m_number = initNumber;
            }

            public int Number
            {
                get { return m_number; }
                set { m_number = value; }
            }

            public int MyMethod(int multiplier)
            {
                return m_number * multiplier;
            }
        }
*/

AssemblyName asmName = new AssemblyName("DynAsm");
//定义动态程序集(AssemblyBuilderAccess.RunAndCollect 表示程序集可以被卸载并且内存会被回收)
AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndCollect);

//定义动态模块
ModuleBuilder moduleBuilder = asmBuilder.DefineDynamicModule("DynModule");

//定义动态类型
TypeBuilder typeBuilder = moduleBuilder.DefineType("DynClass", TypeAttributes.Public | TypeAttributes.Sealed);

//定义字段
FieldBuilder fb = typeBuilder.DefineField("m_number", typeof(int), FieldAttributes.Private);

//定义构造器DynClass(int initNumber)
//1.构造器参数
Type[] paramTypes = new Type[] { typeof(int) };
//2. 生成有参构造器的ILGenerator
ConstructorBuilder ctor1Builder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, paramTypes);
ILGenerator ctor1IL = ctor1Builder.GetILGenerator();
//2.1. 调父类object构造
//加载计算堆栈0号参数（this）
ctor1IL.Emit(OpCodes.Ldarg_0);
//调用父类object构造函数
ctor1IL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
//2.2 赋值 m_number = initNumber;
ctor1IL.Emit(OpCodes.Ldarg_0);
ctor1IL.Emit(OpCodes.Ldarg_1);
//用新值替换在对象引用或指针的字段中存储的值
ctor1IL.Emit(OpCodes.Stfld, fb);
ctor1IL.Emit(OpCodes.Ret);

//定义构造器DynClass() : this(42)
ConstructorBuilder ctor0Builder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
ILGenerator ctor0IL = ctor0Builder.GetILGenerator();
ctor0IL.Emit(OpCodes.Ldarg_0);
//将提供的 int8 值作为 int32 推送到计算堆栈上（短格式）
ctor0IL.Emit(OpCodes.Ldc_I4_S, 42);
ctor0IL.Emit(OpCodes.Call, ctor1Builder);
ctor0IL.Emit(OpCodes.Ret);

//定义属性
PropertyBuilder pb = typeBuilder.DefineProperty("Number", PropertyAttributes.HasDefault, typeof(int), null);
MethodAttributes getSetAttr = MethodAttributes.Public |
            MethodAttributes.SpecialName | MethodAttributes.HideBySig;
//1.get访问器
MethodBuilder numberGetAccessor = typeBuilder.DefineMethod("get_Number", getSetAttr, typeof(int), Type.EmptyTypes);
ILGenerator ngetIL = numberGetAccessor.GetILGenerator();
ngetIL.Emit(OpCodes.Ldarg_0);
ngetIL.Emit(OpCodes.Ldfld, fb);
ngetIL.Emit(OpCodes.Ret);
//2.set访问器
MethodBuilder numberSetAccessor = typeBuilder.DefineMethod("set_Number", getSetAttr, null, new Type[] {typeof(int)});
ILGenerator nsetIL = numberSetAccessor.GetILGenerator();
nsetIL.Emit(OpCodes.Ldarg_0);
nsetIL.Emit(OpCodes.Ldarg_1);
nsetIL.Emit(OpCodes.Stfld, fb);
nsetIL.Emit(OpCodes.Ret);
//3.设置get/set访问器
pb.SetGetMethod(numberGetAccessor);
pb.SetSetMethod(numberSetAccessor);


//定义方法 public int MyMethod(int multiplier)
MethodBuilder myMothodBuilder =typeBuilder.DefineMethod("MyMethod",MethodAttributes.Public,typeof(int),new Type[] {typeof(int)});
ILGenerator myMethodIL = myMothodBuilder.GetILGenerator();
myMethodIL.Emit(OpCodes.Ldarg_0);
myMethodIL.Emit(OpCodes.Ldfld, fb);
myMethodIL.Emit(OpCodes.Ldarg_1);
myMethodIL.Emit(OpCodes.Mul);
myMethodIL.Emit(OpCodes.Ret);

//完成类型创建
Type? t = typeBuilder.CreateType();

MethodInfo mi = t.GetMethod("MyMethod");
PropertyInfo pi = t.GetProperty("Number");
//创建对象测试
object o1 = Activator.CreateInstance(t);

Console.WriteLine("o1.Number: {0}", pi.GetValue(o1, null));
pi.SetValue(o1, 127, null);
Console.WriteLine("o1.Number: {0}", pi.GetValue(o1, null));

object[] arguments = { 22 };
Console.WriteLine("o1.MyMethod(22): {0}",
    mi.Invoke(o1, arguments));

object o2 = Activator.CreateInstance(t,
            new object[] { 5280 });
Console.WriteLine("o2.Number: {0}", pi.GetValue(o2, null));



